#include "hex_bin.h"
#include "alg.h"
namespace SDHuaYi_Script
{

    Hex_Bin::Hex_Bin(QString str, cardReaderDev &Reader, QString addr, int mode)
    {
        bool ok;
        file = str;
        encrypt_mode = mode;
        // encrypt_sm4.set_mode(mode);

        kais_addr = addr.toInt(&ok, 16);
        this->iReader = Reader;
        // encrypt_sm4.InIt();
        // set_sm4_cbc("979EC13B1CBFE9DCD01AB0FED307EAE5","00000000000000000000000000000000");
    }

    bool Hex_Bin::Get_Order()
    {
        switch (Hex_Bin::isHex_or_Bin())
        {
        case 1:
            if (!Hex_Bin::Get_Hex())
            {
                return false;
            }
            if (!Hex_Bin::Hex_verify_all())
            {
                return false;
            }
            Hex_Bin::hex_text();
            Hex_Bin::Erasure_Falsh();
            if (!Hex_Bin::Bin_analysis())
            {
                return false;
            }
            break;
        case 2:
            if (!Hex_Bin::Get_Bin())
            {
                return false;
            }
            Hex_Bin::Erasure_Falsh();
            if (!Hex_Bin::Bin_analysis())
            {
                return false;
            }
            break;
        case 0:
            return false;
            break;
            //    default:
        }
        return true;
    }

    /*
     * 功能：判断文件是否是Hex文件或者Bin文件
     * 返回值：Hex文件返回1    bin文件返回2     其他返回0
     */
    int Hex_Bin::isHex_or_Bin()
    {
        QFileInfo fileinfo(file);
        if (!fileinfo.isFile())
        {
            return false;
        }
        QString file_suffix = fileinfo.suffix();
        if (file_suffix == "ihex")
        {
            return 1;
        }
        else if (file_suffix == "bin")
        {
            return 2;
        }
        else
        {
            return 0;
        }
    }

    void Hex_Bin::hex_text()
    {
        bool ok;
        QString buf = "";
        int addr_data = 0;

        for (int i = 0; i < file_line.size(); ++i)
        {
            if (Hex_Bin::get_type(file_line.at(i)).toInt() == 0)
            {
                addr_data = Hex_Bin::get_addr(file_line.at(i)).toInt(&ok, 16);
                for (int a = 0; a < i; ++a)
                {
                    if (Hex_Bin::get_type(file_line.at(a)).toInt() == 4)
                    {
                        addr_data += (Hex_Bin::get_data(file_line.at(a)).mid(2, 2).toInt(&ok, 16) << 16);
                    }
                }
                break;
            }
        }

        //    qDebug()<<"Hex qis addr = "<<QString::number(addr_data,16);
        kais_addr = addr_data;

        buf.clear();

        for (int i = 0; i < file_line.size(); ++i)
        {
            if (Hex_Bin::get_type(file_line.at(i)).toInt() == 0)
            {
                buf.append(Hex_Bin::get_data(file_line.at(i)));
            }
            else if (Hex_Bin::get_type(file_line.at(i)).toInt() == 1)
            {
                break;
            }
        }

        file_all.clear();
        file_all = buf;
    }

    /*
     * 功能：获取Hex文件数据并将数据放在列表file_line中
     */
    bool Hex_Bin::Get_Hex()
    {
        QFile fh(file);
        if (!fh.open(QIODevice::ReadOnly | QIODevice::Text))
        {
            return false;
        }

        //    qDebug()<<"file size = "<<fh.size();

        QString line;
        QTextStream in(&fh); // 用文件构造流

        line = in.readLine(); // 读取一行放到字符串里

        file_line.append(line); // 数据放入列表
        while (!line.isNull())  // 字符串有内容
        {
            line = in.readLine();   // 循环读取下行
            file_line.append(line); // 数据放入列表
        }

        Hex_Bin::move_Empty();

        fh.close();
        return true;
    }

    /*
     * 功能：去除文件中的空行
     */
    void Hex_Bin::move_Empty()
    {
        for (int i = 0; i < file_line.size(); ++i)
        {
            if (file_line.at(i).isEmpty())
            {
                file_line.removeAt(i);
                --i;
            }
        }
    }

    /*
     * 功能：返回该行数据长度
     */
    QString Hex_Bin::get_len(QString str)
    {
        int num = 0;
        num = str.indexOf(QChar(':'));
        return str.mid(num + DATA_LEN, 2);
    }

    /*
     * 功能：返回该行起始地址
     */
    QString Hex_Bin::get_addr(QString str)
    {
        int num = 0;
        num = str.indexOf(QChar(':'));
        return str.mid(num + DATA_ADD, 4);
    }

    /*
     * 功能：返回该行数据类型
     */
    QString Hex_Bin::get_type(QString str)
    {
        int num = 0;
        num = str.indexOf(QChar(':'));
        return str.mid(num + DATA_TYPE, 2);
    }

    /*
     * 功能：返回该行数据
     */
    QString Hex_Bin::get_data(QString str)
    {
        int num = 0;
        bool ok;
        num = str.indexOf(QChar(':'));
        return str.mid(num + DATA_TEXT, str.mid(num + DATA_LEN, 2).toInt(&ok, 16) * 2);
    }

    /*
     * 功能：返回该行校验位
     */
    QString Hex_Bin::get_verify(QString str)
    {
        int num = 0;
        num = str.size();
        return str.mid(num - 2, 2);
    }

    // void Hex_Bin::set_sm4_cbc(QString key, QString iv)
    //{
    //     encrypt_sm4.set_key(key);
    //     encrypt_sm4.set_iv(iv);
    // }

    /*
     * 功能：检验Hex文件一行数据校验是都正确
     * 参数：要检验的Hex文件中的一行数据
     * 返回值：校验正确，返回true；失败返回false
     *
     * 计算方法：计算从第一个字节以后（不包括‘:’）的所有
     *         各字节的和模256的余。即各字节二进制算术和，
     *         不计超过256的溢出值，然后用0x100减去这个算
     *         数累加和，得出得值就是此行得校验和。
     *
     */
    bool Hex_Bin::Hex_verify(QString str)
    {
        bool ok;
        int num = 0;
        QList<int> data;

        data.append(str.mid(1, 2).toInt(&ok, 16));
        for (int i = 0; i < (data.at(0) + 4); ++i)
        {
            data.append(str.mid(i * 2 + 3, 2).toInt(&ok, 16));
        }
        for (int i = 0; i < (data.size() - 1); ++i) // 获取除校验位外所有数据的和
        {
            num += data.at(i);
        }
        if ((256 - (num % 256) == data.at(data.size() - 1)) || ((num % 256) == 0)) // 检验校验值
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    /*
     * 功能：校验Hex文件所有行的校验是否正确，需要先调用Hex_Bin::Get_Hex()
     * 返回值：全部校验成功返回teue     出现校验错误的返回false
     *
     */
    bool Hex_Bin::Hex_verify_all()
    {
        for (int i = 0; i < file_line.size(); ++i)
        {
            if (!Hex_Bin::Hex_verify(file_line.at(i)))
            {
                return false;
            }
        }
        return true;
    }

    bool Hex_Bin::Get_Bin()
    {
        QFile fh(file);
        if (!fh.open(QIODevice::ReadOnly))
        {
            return false;
        }

        //    qDebug()<<"file bin size = "<<fh.size();

        QByteArray arry = fh.readAll();

        //    qDebug()<<"file bin size = "<<arry.size();

        file_all = arry.toHex();
        // kais_addr = 0;

        //    qDebug()<<"file bin size = "<<file_all.size()/2;

        fh.close();
        return true;
    }

    void Hex_Bin::Erasure_Falsh()
    {
        bool ok;
        QString rall = file_all, lin = "";
        int file_size = file_all.size() / 2;
        int addr_g = kais_addr >> 16, addr_d = kais_addr%65536;

        if (addr_g == 0)
        {
            lin.append("0032").append(QString::number(0, 16).rightJustified(4, '0')).append("00");
            lin = lin.toUpper();
            H_B_line.append(lin);
            lin.clear();
        }
        else
        {
            lin.append("0032").append(QString::number(addr_g, 16).rightJustified(4, '0')).append("00");
            lin = lin.toUpper();
            H_B_line.append(lin);
            lin.clear();
        }

        qDebug() << "file size /256 = " << file_size / 256;

        for (int i = 0; i < file_size / 256; ++i)
        {
            if (addr_d == 65536)
            {
                addr_g++;
                lin.append("0032").append(QString::number(addr_g, 16).rightJustified(4, '0')).append("00");
                lin = lin.toUpper();
                addr_d = 0;
                H_B_line.append(lin);
                lin.clear();
            }

            lin.append("003E").append("00").append(QString::number(addr_d, 16).rightJustified(4, '0').mid(0, 2)).append("00");
            lin = lin.toUpper();
            H_B_line.append(lin);
            lin.clear();
            addr_d += 256;
        }

        if (file_size % 256 != 0)
        {
            lin.append("003E").append("00").append(QString::number(addr_d, 16).rightJustified(4, '0').mid(0, 2)).append("00");
            lin = lin.toUpper();
            H_B_line.append(lin);
            lin.clear();
        }
    }

#if 1
    // 转化为密文指令
    bool Hex_Bin::Bin_analysis()
    {
        QString rall = file_all, lin = "";
        QString buf = "";
        bool ok;

        int len = rall.size();
        int addr_g = kais_addr >> 16, addr_d = kais_addr%65536;
        int len_num = 0;

        if (addr_g == 0)
        {
            lin.append("0032").append(QString::number(0, 16).rightJustified(4, '0')).append("00");
            lin = lin.toUpper();
            H_B_line.append(lin);
            lin.clear();
        }
        else
        {
            lin.append("0032").append(QString::number(addr_g, 16).rightJustified(4, '0')).append("00");
            lin = lin.toUpper();
            H_B_line.append(lin);
            lin.clear();
        }

        for (int i = 0; i < len / 256; ++i)
        {
            if (addr_d == 65536)
            {
                addr_g++;
                lin.append("0032").append(QString::number(addr_g, 16).rightJustified(4, '0')).append("00");
                lin = lin.toUpper();
                addr_d = 0;
                H_B_line.append(lin);
                lin.clear();
            }

            lin.append("0015").append(QString::number(addr_d, 16).rightJustified(4, '0')).append("80");
            lin = lin.toUpper();
            buf = HYALG_SM4Crypt(ALG_MODE_CBC, ALG_ENC, "979EC13B1CBFE9DCD01AB0FED307EAE5", "00000000000000000000000000000000", rall.mid(256 * i, 256));
            buf = buf.toUpper();
            // if(encrypt_sm4.Encrypt(&buf,&len_num,rall.mid(256 * i,256),128) == false)
            // {
            //     qDebug()<<"SM4_Encrypt err!!";
            //     return false;
            // }

            lin.append(buf);
            H_B_line.append(lin);

            lin.clear();
            buf.clear();
            addr_d += 128;
        }

        if (len % 256)
        {
            int end_len = len % 256;
            QString end_line = rall.mid((len / 256) * 256, end_len);
            for (int i = 0; i < (256 - end_len); ++i)
            {
                end_line.append("F");
            }

            lin.append("0015").append(QString::number(addr_d, 16).rightJustified(4, '0'));
            lin = lin.toUpper();

            lin.append(QString::number(end_line.size() / 2, 16).rightJustified(2, '0'));
            buf = HYALG_SM4Crypt(ALG_MODE_CBC, ALG_ENC, "979EC13B1CBFE9DCD01AB0FED307EAE5", "00000000000000000000000000000000", end_line);
            buf = buf.toUpper();
            // if(encrypt_sm4.Encrypt(&buf,&len_num,end_line,end_line.size()/2) == false)
            // {
            //     qDebug()<<"SM4_Encrypt err!!";
            //     return false;
            // }

            lin.append(buf);
            H_B_line.append(lin);
            lin.clear();
        }
        return true;
    }

    bool Hex_Bin::Send_Cos()
    {
        for (int i = 0; i < H_B_line.size(); ++i)
        {
            if (iReader.SendAPDU(H_B_line.at(i)) == false)
            {
                return false;
            }
            if (iReader.m_ss != "9000")
            {
                return false;
            }
        }
        return true;
    }
#else
    // 转化为明文指令
    void Hex_Bin::Bin_analysis()
    {
        QString rall = file_all, lin = "";

        int len = rall.size();
        int addr = 0;

        for (int i = 0; i < len / 256; ++i)
        {
            lin.append("00 15 ").append(QString::number(addr, 16).rightJustified(4, '0')). // 地址
                append(" 80 ")
                    .                           // 长度
                append(rall.mid(256 * i, 256)); // 数据
            H_B_line.append(lin);
            lin.clear();
            addr += 128;
        }

        if (len % 256)
        {
            qDebug() << (len / 256) * 256 << " " << len - len % 256 << " " << len << " " << len % 256;
            lin.append("00 15 ").append(QString::number(addr, 16).rightJustified(4, '0')). // 地址
                append(" ")
                    .append(QString::number((len % 256) / 2, 16).rightJustified(2, '0'))
                    . // 长度
                append(" ")
                    .append(rall.mid((len / 256) * 256, len % 256)); // 数据
            H_B_line.append(lin);
            lin.clear();
        }
    }
#endif

#if 0

bool Hex_Bin::Hex_analysis()
{
    if(at_num < file_line.size())
    {
        switch(Hex_Bin::get_type(file_line.at(at_num)).toInt())
        {
        case 0:
            Hex_Bin::Hex_type0();
            break;
        case 1:
            Hex_Bin::Hex_type1();
            return false;
            break;
        case 2:
            Hex_Bin::Hex_type2();
            break;
        case 3:
            Hex_Bin::Hex_type3();
            break;
        case 4:
            Hex_Bin::Hex_type4();
            break;
        case 5:
            Hex_Bin::Hex_type5();
            break;
        }
        return true;
    }else{
        return false;
    }
}


void Hex_Bin::Hex_type0()
{
    QString str1 = "",str2 = "";
    int data_len = 0,at_l = at_num;
    bool ok;
    str1.append("00 15 ").append(Hex_Bin::get_addr(file_line.at(at_num))).append(" ");
    str2.append(Hex_Bin::get_data(file_line.at(at_num)));
    data_len += Hex_Bin::get_len(file_line.at(at_num)).toInt(&ok,16);
    at_l++;
    for(int i = 0;i < (file_line.size() - at_num);++i)
    {
        if(Hex_Bin::get_type(file_line.at(at_num + i + 1)) == QString("00")
                && (Hex_Bin::get_addr(file_line.at(at_num + i)).toInt(&ok,16)
                    + Hex_Bin::get_len(file_line.at(at_num + i)).toInt(&ok,16)
                    == Hex_Bin::get_addr(file_line.at(at_num + i + 1)).toInt(&ok,16)))
        {
            if(data_len + Hex_Bin::get_len(file_line.at(at_num + i + 1)).toInt(&ok,16) > 128)
            {
                break;
            }else{
                data_len += Hex_Bin::get_len(file_line.at(at_num + i + 1)).toInt(&ok,16);
                str2.append(Hex_Bin::get_data(file_line.at(at_num + i + 1)));
                at_l++;
            }
        }else{
            break;
        }
    }
    str1.append(QString::number(data_len,16)).rightJustified(4,'0').append(" ").append(str2);
    H_B_line.append(str1);
    at_num = at_l;
    str1.clear();
    str2.clear();
}
void Hex_Bin::Hex_type1()
{
    at_num++;
}
void Hex_Bin::Hex_type2()
{
    at_num++;
}
void Hex_Bin::Hex_type3()
{
    at_num++;
}
void Hex_Bin::Hex_type4()
{
    QString str1 = "";
    str1.append("00 32 00 ").append(Hex_Bin::get_data(Hex_Bin::get_type(file_line.at(at_num))).mid(2,2)).append(" 00");
    H_B_line.append(str1);
    at_num++;
    str1.clear();
}
void Hex_Bin::Hex_type5()
{
    at_num++;
}



void Hex_Bin::Hex_analysis()
{
    QString lin,lin1;
    int len = 0;
    bool ok;
    for(int i = 0; i < file_line.size(); ++i)
    {
        if(Hex_Bin::get_type(file_line.at(i)) == QString("00"))
        {
            lin.append("00 15 ").append(Hex_Bin::get_addr(file_line.at(i))).append(" ");
            for(int j = i;j < file_line.size(); ++j)
            {
                if(Hex_Bin::get_type(file_line.at(i)) == QString("00"))
                {
                    if((len + Hex_Bin::get_len(file_line.at(j)).toInt(&ok, 16)) <= 128)
                    {
                        lin1.append(Hex_Bin::get_data(file_line.at(j)));
                        len += Hex_Bin::get_len(file_line.at(j)).toInt(&ok, 16);
                    }else{
                        i = (j - 1);
                        lin.append(QString::number(len,16)).append(" ").append(lin1);
                        H_B_line.append(lin);
                        lin.clear();
                        lin1.clear();
                        break;
                    }

                }
            }
        }else if(Hex_Bin::get_type(file_line.at(i)) == QString("04"))
        {
            lin.append("00 32 00 ").append(Hex_Bin::get_data(file_line.at(i).mid(2,2))).append(" 00");
            H_B_line.append(lin);
            lin.clear();
        }
    }
}
#endif
}
